package com.rock.upms.svc.upms.service.impl;

import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import com.rock.common.base.BaseConstants;
import com.rock.common.util.ByteUtil;
import com.rock.common.util.MD5Util;
import com.rock.common.util.RedisUtil;
import com.rock.common.util.RockJsonUtil;
import com.rock.common.util.SerializeUtil;
import com.rock.common.util.StringUtil;
import com.rock.upms.api.model.service.IUpmsPersonService;
import com.rock.upms.api.model.service.IUpmsThirdBindService;
import com.rock.upms.api.upms.service.IAuthService;
import com.rock.upms.api.upms.service.ILoginService;
import com.rock.upms.api.upms.service.IUpmsService;
import com.rock.upms.model.UpmsPerson;
import com.rock.upms.model.UpmsPersonExample;
import com.rock.upms.model.UpmsPersonExample.Criteria;
import com.rock.upms.model.UpmsThirdBind;
import com.rock.upms.model.UpmsThirdBindExample;
import com.rock.upms.model.UpmsUser;
import com.rock.upms.model.dto.PermissionDto;
import com.rock.upms.model.dto.PrimaryLoginResult;
import com.rock.upms.model.dto.RoleDto;
import com.rock.upms.model.dto.ThirdComLoginDto;
import com.rock.upms.model.dto.UpmsRedisKey;
import com.rock.upms.model.dto.UserDto;
import com.rock.upms.model.dto.UserInfo;

/**
 * 
 * @Description:登录服务
 * @author: hotdog
 * @date: 2018年7月31日 下午4:27:22
 * @Copyright: v1.0
 *
 */
@Repository
@Service
public class LoginService implements ILoginService {

	private static final Logger log = LoggerFactory.getLogger(LoginService.class);
	@Autowired
	private IUpmsPersonService upmsPersonService;
	@Autowired
	private IUpmsService upmsService;
	@Autowired
	private IUpmsThirdBindService upmsThirdBindService;
	@Autowired
	private IAuthService authService;

	/**
	 * 密码登录服务<br>
	 * 1 先判断该用户是否已经登录<br>
	 * 2已经登录的则直接返回ptoken<br>
	 * 3未登录则 获取用户信息<br>
	 * 4 写入缓存
	 */
	@Override
	public PrimaryLoginResult primaryLoginByPassword(String usercode, String pwd) {
		// primaryLogoutByUsercode(usercode);// 先退出登录
		PrimaryLoginResult loginResult = new PrimaryLoginResult();
		String primarytoken = authService.getPTokenByUsercode(usercode);
		if (StringUtil.isNotBlank(primarytoken)) {
			log.trace("===>run 密码登录: " + usercode + " 已登录过，直接返回primarytoken：" + primarytoken);
			loginResult.setPrimarytoken(primarytoken);
			loginResult.setCode(BaseConstants.SUCC);
			loginResult.setMsg("登录成功（已登录过）");
			return loginResult;
		}
		log.trace("===>run 密码登录 service ");
		if (StringUtil.isBlank(usercode) || StringUtil.isBlank(pwd)) {
			loginResult.setCode(BaseConstants.FAIL);
			loginResult.setMsg("用户名或密码不能为空");
			log.trace("===>用户名或密码不能为空");
			return loginResult;
		}
		UpmsPersonExample example = new UpmsPersonExample();
		Criteria criteria = example.createCriteria();
		criteria.andUsercodeEqualTo(usercode);
		UpmsPerson person = upmsPersonService.selectFirstByExample(example);
		if (person != null) {
			String datapassword = person.getPassword();
			try {
				if (MD5Util.validPassword(pwd, datapassword, person.getSalt())) {
					return putPTokenObjInRedis(usercode, loginResult);
				} else {
					loginResult.setCode(BaseConstants.INVLAID_PWD);
					loginResult.setMsg("密码错误");
					log.trace("===>密码错误");
					return loginResult;
				}
			} catch (NoSuchAlgorithmException e) {
				e.printStackTrace();
				loginResult.setCode(BaseConstants.FAIL);
				loginResult.setMsg(e.getMessage());
				log.trace("===>抛异常：" + e.getMessage());
				return loginResult;
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
				loginResult.setCode(BaseConstants.FAIL);
				loginResult.setMsg(e.getMessage());
				log.trace("===>抛异常：" + e.getMessage());
				return loginResult;
			}
		} else {
			loginResult.setCode(BaseConstants.INVLAID_USERCODE);
			loginResult.setMsg("账户不存在");
			log.trace("===>账户不存在");
			return loginResult;
		}
	}

	/**
	 * 无密登录服务<br>
	 * 1 先判断该用户是否已经登录<br>
	 * 2已经登录的则直接返回ptoken<br>
	 * 3未登录则 获取用户信息<br>
	 * 4 写入缓存
	 */
	@Override
	public PrimaryLoginResult primaryLoginNoPassword(String usercode) {
		// primaryLogoutByUsercode(usercode);// 先退出登录
		PrimaryLoginResult loginResult = new PrimaryLoginResult();
		String primarytoken = authService.getPTokenByUsercode(usercode);
		if (StringUtil.isNotBlank(primarytoken)) {
			log.trace("===>run 无密码登录: " + usercode + " 已登录过，直接返回primarytoken：" + primarytoken);
			loginResult.setPrimarytoken(primarytoken);
			loginResult.setCode(BaseConstants.SUCC);
			loginResult.setMsg("登录成功（已登录过）");
			return loginResult;
		}
		log.trace("===>run 无密码登录 ：" + usercode);
		if (StringUtil.isBlank(usercode)) {
			loginResult.setCode(BaseConstants.FAIL);
			loginResult.setMsg("用户名不能为空");
			log.trace("===>用户名不能为空");
			return loginResult;
		}
		UpmsPersonExample example = new UpmsPersonExample();
		Criteria criteria = example.createCriteria();
		criteria.andUsercodeEqualTo(usercode);
		UpmsPerson person = upmsPersonService.selectFirstByExample(example);
		if (person != null) {
			// 写入缓存
			return putPTokenObjInRedis(usercode, loginResult);
		} else {
			loginResult.setCode(BaseConstants.INVLAID_USERCODE);
			loginResult.setMsg("账户不存在");
			log.trace("===>账户不存在");
			return loginResult;
		}
	}

	/**
	 * 登出<br>
	 * 1 根据usercode 获取primarytoken<br>
	 * 2 移除primarytoken包含的对象<br>
	 * 3 移除usercode对应的primarytoken<br>
	 */
	@Override
	public boolean primaryLogoutByUsercode(String usercode) {
		byte[] usercodeByte = ByteUtil.getByteKey(UpmsRedisKey.USERCODE_KEY_PREFIX, usercode);
		byte[] primarytokenByte = RedisUtil.get(usercodeByte);
		if (primarytokenByte != null) {
			String primarytoken = (String) SerializeUtil.deserialize(primarytokenByte);// primarytokenByte.toString();//
																						// (String)
																						// SerializeUtil.deserialize(primarytokenByte);
			// 移除session
			log.trace("===>移除primarytoken：" + primarytoken);
			RedisUtil.remove(ByteUtil.getByteKey(UpmsRedisKey.PRIMARY_TOKEN_KEY_PREFIX, primarytoken));
			// 移除primarytoken
			log.trace("===>移除usercode：" + usercode);
			RedisUtil.remove(usercodeByte);
		}
		return true;
	}

	/**
	 * 第三方登录服务<br>
	 * 1、根据thirdId、thirdCode找到绑定的mobilephone<br>
	 * 2、根据mobilephone找到人员信息<br>
	 * 3、根据人员信息做无密登录<br>
	 */
	@Override
	public ThirdComLoginDto thirdComLogin(String thirdId, String thirdComcode) {
		ThirdComLoginDto resultDto = new ThirdComLoginDto();
		UpmsThirdBindExample bindExample = new UpmsThirdBindExample();
		com.rock.upms.model.UpmsThirdBindExample.Criteria bindCriteria = bindExample.createCriteria();
		bindCriteria.andThirdIdEqualTo(thirdId);
		bindCriteria.andThirdComcodeEqualTo(thirdComcode);
		bindCriteria.andIsDeletedEqualTo(BaseConstants.NOT_DELETED);
		// 1 查绑定信息
		UpmsThirdBind upmsThirdBind = upmsThirdBindService.selectFirstByExample(bindExample);
		if (upmsThirdBind == null) {
			resultDto.setCode(BaseConstants.NOT_EXIST_BIND);
			log.trace("===>未查到绑定信息");
			resultDto.setMsg("未绑定");
			return resultDto;
		} else {
			// 2 查人员信息
			UpmsPersonExample personExample = new UpmsPersonExample();
			com.rock.upms.model.UpmsPersonExample.Criteria personCriteria = personExample.createCriteria();
			personCriteria.andMobilephoneEqualTo(upmsThirdBind.getMobilephone());
			personCriteria.andIsDeletedEqualTo(BaseConstants.NOT_DELETED);
			UpmsPerson person = upmsPersonService.selectFirstByExample(personExample);
			if (person == null) {
				resultDto.setCode(BaseConstants.NOT_EXIST_PERSON);
				resultDto.setMsg("绑定的员工信息不存在");
				return resultDto;
			} else {
				// 调用无密登录实现登录
				PrimaryLoginResult loginResult = primaryLoginNoPassword(person.getUsercode());
				if (loginResult.getCode() == BaseConstants.SUCC) {
					resultDto.setCode(BaseConstants.SUCC);
					resultDto.setMsg("主账户登录成功");
					resultDto.setPrimaryToken(loginResult.getPrimarytoken());
				} else {
					resultDto.setCode(loginResult.getCode());
					resultDto.setMsg(loginResult.getMsg());
				}
			}
		}
		return resultDto;
	}

	/**
	 * 获取user信息，根据ptoken获取user
	 */
	@Override
	public UserDto getUserByPToken(String ptoken) {
		log.trace("===>获取user入参，ptoken:" + ptoken);
		byte[] userByte = RedisUtil.hget(ByteUtil.getByteKey(UpmsRedisKey.PRIMARY_TOKEN_KEY_PREFIX, ptoken), UpmsRedisKey.HASH_KEY_USER.getBytes());
		if (userByte != null) {
			UserDto user = (UserDto) SerializeUtil.deserialize(userByte);
			log.trace("===>获取user出参，user:" + RockJsonUtil.toJson(user));
			return user;
		} else {
			log.trace("===>获取user出参，user:null");
			return null;
		}
	}

	/**
	 * 将token对象写入缓存<br>
	 * 1 生成token，为uuid<br>
	 * 2 设置key-value：usercode---->primarytoken<br>
	 * 3 设置HashMap：<br>
	 * primarytoken-->user<br>
	 * primarytoken-->roles<br>
	 * primarytoken-->permission<br>
	 * 
	 * @param usercode
	 * @param loginResult
	 * @return
	 */
	private PrimaryLoginResult putPTokenObjInRedis(String usercode, PrimaryLoginResult loginResult) {
		loginResult.setCode(BaseConstants.SUCC);
		loginResult.setMsg("登录成功");
		// 生成rocktoken
		String primarytoken = UUID.randomUUID().toString();
		log.trace("===>primarytoken:" + primarytoken);
		loginResult.setPrimarytoken(primarytoken);
		HashMap<String, Object> sessionMap = getRoleAndPermission(usercode);
		UserDto user = (UserDto) sessionMap.get(UpmsRedisKey.HASH_KEY_USER);
		Set<String> roles = (Set<String>) sessionMap.get(UpmsRedisKey.HASH_KEY_ROLES);
		Set<String> permissions = (Set<String>) sessionMap.get(UpmsRedisKey.HASH_KEY_PERMISSIONS);
		log.trace("===>" + primarytoken + "<--->roles:" + RockJsonUtil.toJson(roles));
		log.trace("===>" + primarytoken + "<--->permissions:" + RockJsonUtil.toJson(permissions));
		// 写入缓存
		RedisUtil.set(ByteUtil.getByteKey(UpmsRedisKey.USERCODE_KEY_PREFIX, usercode), SerializeUtil.serialize(primarytoken));// 用户对应的token
		RedisUtil.hset(ByteUtil.getByteKey(UpmsRedisKey.PRIMARY_TOKEN_KEY_PREFIX, primarytoken), UpmsRedisKey.HASH_KEY_USER.getBytes(), SerializeUtil.serialize(user));
		RedisUtil.hset(ByteUtil.getByteKey(UpmsRedisKey.PRIMARY_TOKEN_KEY_PREFIX, primarytoken), UpmsRedisKey.HASH_KEY_ROLES.getBytes(), SerializeUtil.serialize(roles));
		RedisUtil.hset(ByteUtil.getByteKey(UpmsRedisKey.PRIMARY_TOKEN_KEY_PREFIX, primarytoken), UpmsRedisKey.HASH_KEY_PERMISSIONS.getBytes(),
				SerializeUtil.serialize(permissions));
		return loginResult;
	}

	/**
	 * 获取角色 权限集合
	 * 
	 * @param usercode
	 * @return
	 */
	private HashMap<String, Object> getRoleAndPermission(String usercode) {
		HashMap<String, Object> map = new HashMap<>();
		UpmsUser user = upmsService.getDefaultUser(usercode);
		UserInfo userinfo = upmsService.getUserInfoByUpmsUser(user);
		map.put(UpmsRedisKey.HASH_KEY_USER, userinfo.getUser());
		Set<String> roles = new HashSet<>();
		// roles.add("login");// 登录成功的均有该角色
		// 角色信息
		for (RoleDto upmsRole : userinfo.getRoleList()) {
			if (StringUtils.isNotBlank(upmsRole.getRoleCode())) {
				roles.add(upmsRole.getRoleCode());
			}
		}
		map.put(UpmsRedisKey.HASH_KEY_ROLES, roles);
		Set<String> permissions = new HashSet<>();
		// 权限信息
		for (PermissionDto permissionDto : userinfo.getPermissionList()) {
			if (StringUtils.isNotBlank(permissionDto.getPermissionValue())) {
				permissions.add(permissionDto.getPermissionValue());
			}
		}
		map.put(UpmsRedisKey.HASH_KEY_PERMISSIONS, permissions);
		return map;
	}

	@Override
	public boolean primaryLogoutByPToken(String ptoken) {
		UserDto user = getUserByPToken(ptoken);
		if (user != null) {
			return primaryLogoutByUsercode(user.getUsercode());
		} else {
			return false;
		}
	}
}
